<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Synchronous Communication
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora176.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora178.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Synchronous Communication</H2> <A NAME="@fonctions457"></A>
Module <TT>Event</TT> from the thread library implements the
communication of assorted values between two processes through
particular ``communication channels''. The effective communication of
the value is synchronized through send and receive events.<BR>
<BR>
This model of communication synchronized by events allows the transfer
through typed channels of the values of the language, including closures,
objects, and events.<BR>
<BR>
It is described in [<A HREF="book-ora214.html#Reppy-th"><CITE>Rep99</CITE></A>].<BR>
<BR>
<A NAME="toc263"></A>
<H3> Synchronization using Communication Events</H3><A NAME="@fonctions458"></A>
<A NAME="@fonctions459"></A>
The primitive communication events are:
<UL>
<LI>
 <TT>send c v </TT> sends a value <TT>v</TT> on the channel <TT>c</TT>;

<LI> <TT>receive c </TT> receives a value on the channel <TT>c</TT>
</UL>
<A NAME="@fonctions460"></A>So as to implement the physical action with which they are associated,
two events should be synchronized. For this purpose, we introduce an operation
of synchronization (<TT>sync</TT>) on events. The sending and
receiving of a value are not effective unless the two communicating
processes are in phase. If a single process wishes to synchronize
itself, the operation gets blocked, waiting for the second process to perform
its synchronization. This implies that a sender wishing to synchronize
the sending of a value (sync<CODE> </CODE><TT>(</TT>send<CODE> </CODE>c<CODE> </CODE>v<TT>)</TT>) can find itself
blocked waiting for a synchronization from a receiver
(sync<CODE> </CODE><TT>(</TT>receive<CODE> </CODE>c<TT>)</TT>).<BR>
<BR>
<A NAME="toc264"></A>
<H3> Transmitted Values</H3>
The communication channels through which the exchanged values
travel are typed: Nothing prevents us from creating multiple channels
for communicating each type of value. As this communication takes
place between Objective CAML threads, any value of the language can be sent
on a channel of the same type. This is useful for closures, objects,
and also events, for a ``relayed'' synchronization request.<BR>
<BR>
<A NAME="toc265"></A>
<H3> Module <TT>Event</TT></H3>
The values encapsulated in communication events travel through
communication channels of the abstract data type <I>'a channel</I>.
The creation function for channels is:


<PRE><BR># Event.new_channel<CODE> </CODE>;;<BR><CODE>- : unit -&gt; 'a Event.channel = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Send and receive events are created by a function call:


<PRE><BR># Event.send<CODE> </CODE>;;<BR><CODE>- : 'a Event.channel -&gt; 'a -&gt; unit Event.event = &lt;fun&gt;</CODE><BR># Event.receive<CODE> </CODE>;;<BR><CODE>- : 'a Event.channel -&gt; 'a Event.event = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
We can consider the functions <TT>send</TT> and <TT>receive</TT> as
constructors of the abstract type <I>'a event</I>. The event
constructed by send does not preserve the information about the type
of the value to transmit (type <I>unit Event.event</I>). On the
other hand, the receive event takes account of it to recover the value
during a synchronization. These functions are non-blocking in the
sense that the transmission of a value does not take place until the
time of the synchronization of two processes by the function:


<PRE><BR># Event.sync<CODE> </CODE>;;<BR><CODE>- : 'a Event.event -&gt; 'a = &lt;fun&gt;</CODE><BR>

</PRE>

This function may be blocking for the sender and the receiver.<BR>
<BR>
There is a non-blocking version:


<PRE><BR># Event.poll<CODE> </CODE>;;<BR><CODE>- : 'a Event.event -&gt; 'a option = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
This function verifies that another process is waiting for synchronization.<BR>
<BR>
If this is the case, it performs the transmissions, and returns the
value <TT>Some v</TT>, if <TT>v</TT> is the value associated with the
event, and <TT>None</TT> otherwise. The received message, extracted
by the function <TT>sync</TT>, can be the result of a more or less
complicated process, triggering other exchanges of messages.<BR>
<BR>

<H5> Example of synchronization.</H5>
We define three threads. The first, <TT>t1</TT>, sends a chain of
characters on channel <TT>c</TT> (function <TT>g</TT>) shared by
all the processes. The two others <TT>t2</TT> and <TT>t3</TT> wait
for a value on the same channel. Here are the functions executed by
the different processes:<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Event.new_channel<CODE> </CODE>();;<BR><CODE>val c : '_a Event.channel = &lt;abstr&gt;</CODE><BR># <B>let</B><CODE> </CODE>f<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ids<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string_of_int<CODE> </CODE><TT>(</TT>Thread.id<CODE> </CODE><TT>(</TT>Thread.self<CODE> </CODE>()<TT>)</TT><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT><CODE>"-------- before  -------"</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>ids<TT>)</TT><CODE> </CODE>;<CODE> </CODE>print_newline()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>e<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Event.receive<CODE> </CODE>c<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT><CODE>"-------- during  -------"</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>ids<TT>)</TT><CODE> </CODE>;<CODE> </CODE>print_newline()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>v<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Event.sync<CODE> </CODE>e<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT>v<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>" "</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>ids<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>" "</CODE><TT>)</TT><CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT><CODE>"-------- after  -------"</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>ids<TT>)</TT><CODE> </CODE>;<CODE> </CODE>print_newline()<CODE> </CODE>;;<BR><CODE>val f : unit -&gt; unit = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>g<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ids<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string_of_int<CODE> </CODE><TT>(</TT>Thread.id<CODE> </CODE><TT>(</TT>Thread.self<CODE> </CODE>()<TT>)</TT><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT><CODE>"Start of "</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>ids<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>"\n"</CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>e2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Event.send<CODE> </CODE>c<CODE> </CODE><CODE>"hello"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Event.sync<CODE> </CODE>e2<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_string<CODE> </CODE><TT>(</TT><CODE>"End of "</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>ids<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_newline<CODE> </CODE>()<CODE> </CODE>;;<BR><CODE>val g : unit -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The three processes are created and executed:


<PRE><BR># <B>let</B><CODE> </CODE>t1<CODE>,</CODE>t2<CODE>,</CODE>t3<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Thread.create<CODE> </CODE>f<CODE> </CODE>()<CODE>,</CODE><CODE> </CODE>Thread.create<CODE> </CODE>f<CODE> </CODE>()<CODE>,</CODE><CODE> </CODE>Thread.create<CODE> </CODE>g<CODE> </CODE>();;<BR><CODE>val t1 : Thread.t = &lt;abstr&gt;</CODE><BR><CODE>val t2 : Thread.t = &lt;abstr&gt;</CODE><BR><CODE>val t3 : Thread.t = &lt;abstr&gt;</CODE><BR># Thread.delay<CODE> </CODE><CODE>1</CODE><CODE>.</CODE><CODE>0</CODE>;;<BR><CODE>Start of 5</CODE><BR><CODE>-------- before  -------6</CODE><BR><CODE>-------- during  -------6</CODE><BR><CODE>hello 6 -------- after  -------6</CODE><BR><CODE>-------- before  -------7</CODE><BR><CODE>-------- during  -------7</CODE><BR><CODE>End of 5</CODE><BR><CODE>- : unit = &lt;unknown constructor&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The transmission may block. The trace of 
<TT>t1</TT> is displayed after the synchronization traces of
<TT>t2</TT> and <TT>t3</TT>. Only one of the two processes <TT>t1</TT> or
<TT>t2</TT> is really terminated, as the following calls show:


<PRE><BR># Thread.kill<CODE> </CODE>t1;;<BR><CODE>- : unit = ()</CODE><BR># Thread.kill<CODE> </CODE>t2;;<BR><CODE>Uncaught exception: Failure("Thread.kill: killed thread")</CODE><BR>

</PRE>
<BR>
<BR>
<HR>
<A HREF="book-ora176.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora178.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
